


#include "chapter1_2.h"

#include <utility>
#include <map>
using namespace std;

/* base type */

typedef pair<int , int> LocXY;		/* line , index_in_line */
//typedef pair<string, int> LocLine;
typedef vector<string> VWord;
typedef pair<string, LocXY> Loc;	/* word--line + index_in_line */
typedef vector<Loc> VLoc;


int GetWord(string line,VWord *pv_word );

class BaseQuery
{
public:
	BaseQuery() {};
	~BaseQuery() {};

	virtual void eval() = 0;

	void build_map(string fname);
	vector<string> input_string;
	void push_word(string a);
	void clear_word( );
	void hitword(string in);
	VLoc _loc;
	void display();

	static VLoc *loc_all_word;
	static VWord *loc_all_line;

private:
	


};
VLoc *BaseQuery::loc_all_word = NULL;
VWord *BaseQuery::loc_all_line = NULL;

void BaseQuery::build_map(std::string fname)
{
	string line_txt;
	int line_num = 0;

	if(loc_all_word == NULL)
		loc_all_word = new VLoc;
	if(loc_all_line == NULL)
		loc_all_line = new VWord;

	loc_all_word->clear();
	loc_all_line->clear();

	ifstream infp(fname.c_str( ), ios::in);
	if(infp.is_open( ) == false)
	{
		printf("Fail to open %s", fname.c_str( ));
	}

	VLoc all_word_loc;
	VWord all_line;
	
	while(0 != getline(infp,line_txt, '\n'))
	{
		int word_num;
		VWord loc_word;	
		VWord::iterator  iter = loc_word.begin( );
		
		loc_all_line->push_back(line_txt);

		word_num = GetWord(line_txt, &loc_word);
		iter = loc_word.begin( );
		for(int i = 0; i < word_num; i++, iter++)
		{
			Loc tmp_loc;

			tmp_loc.first = *iter;
			tmp_loc.second.first = line_num;
			tmp_loc.second.second = i;
			loc_all_word->push_back(tmp_loc);		
		}

		line_num++;		
	}

}

void BaseQuery::push_word(string a)
{
	VWord v_word;
	//BaseQuery *pq = NULL;
	int num = GetWord(a , &v_word);

	VWord::iterator it;
	for(it = v_word.begin(); it < v_word.end(); it++)
		this->input_string.push_back(*it);	
}
void BaseQuery::clear_word( )
{
	this->input_string.clear( );	
}

void BaseQuery::display( )
{
	VLoc::iterator it;
	
	printf("\n *********************************************************");	

	if(true == _loc.empty())
		printf("\n No word find !");	

	for(it = _loc.begin(); it < _loc.end(); it++)
	{		
		printf("\n Input value = %s", it->first.c_str());
		printf("\n Hit line = %d,num = %d, line_txt = %s", it->second.first, it->second.second, (*loc_all_line)[it->second.first].c_str());	
	}
	printf("\n *********************************************************");
	
}




/************************************ Derived class ******************************************/
class StrQuery : public BaseQuery
{
public:
	void eval( );
	StrQuery() {};
	~StrQuery() {};

};
void StrQuery::eval( )
{
	VLoc::iterator it;
	VWord::iterator it_line = loc_all_line->begin();

	string in = input_string[0];
	_loc.clear( );
	for(it = loc_all_word->begin(); it < loc_all_word->end(); it++)
	{
		if(strcmp(it->first.c_str(), in.c_str()) == 0)
		{
			//printf("\n Hit line = %d,num = %d, line_txt = %s", it->second.first, it->second.second, (*loc_all_line)[it->second.first].c_str());	
			//break;
			_loc.push_back(*it);
		}
	}
	
}

class AndQuery : public BaseQuery
{
public:
	void eval( );	


};
void AndQuery::eval( )
{

}


class OrQuery : public BaseQuery
{
public:
	void eval( );
};

void OrQuery::eval( )
{
	VLoc::iterator it;
	VWord::iterator it_line = loc_all_line->begin();

	vector<string>::iterator its = input_string.begin();

	_loc.clear( );
	while(its < input_string.end())
	{
		for(it = loc_all_word->begin(); it < loc_all_word->end(); it++)
		{
			if(strcmp(it->first.c_str(), its->c_str()) == 0)
			{
				//printf("\n Hit line = %d,num = %d, line_txt = %s", it->second.first, it->second.second, (*loc_all_line)[it->second.first].c_str());	
				//break;
				_loc.push_back(*it);
			}			
		}
		its++;
	}
}

/*  user query ---------process user input */

class UserQuery
{
public:
	UserQuery( ) {pq_str = NULL; pq_or = NULL;};

	BaseQuery *QueryInit( string fname, string input);
	BaseQuery *QueryEval( string input);
	void QueryTxt( string input);
	BaseQuery *pq_str;
	BaseQuery *pq_or;
	BaseQuery *pq;
};

BaseQuery *UserQuery::QueryEval(string input)
{
	VWord v_word;
	VWord::iterator it;
	int num = GetWord(input , &v_word);

	if( num == 1){
		pq_str = new StrQuery;
		pq = pq_str;
	}
	else if(num > 1){
		pq_or = new OrQuery;	
		pq = pq_or;
	}	
	return pq;
}

BaseQuery *UserQuery::QueryInit( string fname,string input)
{
	VWord v_word;
	VWord::iterator it;
	int num = GetWord(input , &v_word);
	
	pq = QueryEval(input);

	for(it = v_word.begin(); it < v_word.end(); it++)
		pq->push_word(*it);

	pq->build_map(fname);

	return pq;
}

void UserQuery::QueryTxt( string input)
{
	VWord v_word;
	VWord::iterator it;
	int num = GetWord(input , &v_word);

	pq = QueryEval(input);

	pq->clear_word( );
	for(it = v_word.begin(); it < v_word.end(); it++)
		pq->push_word(*it);

	pq->eval();
	pq->display();
	
}




void test_query( )
{
	UserQuery uq ;
	BaseQuery *pq = NULL;

	pq = uq.QueryInit( "infile.txt", "ccc");
	if(pq)
		pq->eval();
	uq.QueryTxt("jjjj");
	uq.QueryTxt("aa ggg");

	delete pq;
}



int GetWord(string line,VWord *pv_word  )
{	
	line.push_back(' ');
	string::size_type line_lens = line.length();
	string::size_type pos = 0, num = 0;
	char *word = new char[line_lens];

	
	while( -1 != (pos = line.find(' ')))
	{
		memset(word, 0 , line_lens);		
		
		if(pos == 0){
			line = line.substr(1, line_lens--);
			continue;
		}
		line.copy(word, pos, 0);		
		pv_word->push_back(word);

		num++;	
		line_lens -= pos;
		line = line.substr(pos, line_lens);
	}

	return num;
}